package fi.jamk.ourcookingapp.activity;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;

import org.json.JSONException;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.InputType;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.inputmethod.EditorInfo;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;
import fi.jamk.ourcookingapp.R;
import fi.jamk.ourcookingapp.backend.MyTools;
import fi.jamk.ourcookingapp.backend.architecture.services.DownloadImageService;
import fi.jamk.ourcookingapp.backend.exceptions.EmptyInputException;
import fi.jamk.ourcookingapp.backend.exceptions.NoIngredientsException;
import fi.jamk.ourcookingapp.backend.exceptions.NoReceiptException;
import fi.jamk.ourcookingapp.backend.exceptions.NoResultException;
import fi.jamk.ourcookingapp.backend.exceptions.NoStepsException;
import fi.jamk.ourcookingapp.backend.model.Comment;
import fi.jamk.ourcookingapp.backend.model.Ingredient;
import fi.jamk.ourcookingapp.backend.model.Receipt;
import fi.jamk.ourcookingapp.backend.model.Step;

/**
 * This activity is for adding a new receipt
 * @author Marius
 */
public class AddReceiptActivity extends Activity {

	protected static final int CAMERA_REQUEST = 123;

	private ImageView imgReceipt;
	
	private List<Ingredient> lstIngredient;
	private List<String> lstIngString = new ArrayList<String>();
	private List<EditText> lstIngs = new ArrayList<EditText>();
	private int[] contentsIng = {R.id.spinIng1, R.id.spinIng2, R.id.spinIng3, R.id.spinIng4, R.id.spinIng5, R.id.spinIng6};
	private int cntContentsIng = 0;
	
	private int[] contentsStep = {R.id.step1, R.id.step2, R.id.step3, R.id.step4, R.id.step5, R.id.step6};
	private int cntContentsStep = 0;
	
	private static final int MAX_ING = 5;
	private static final int MAX_STEP = 5;

	private static final int WIDHT_COMMENT = 350;

	private static final int WIDTH_STEP = 300;

	public static final int IMAGE_SCALE = 400;
	
	private List<EditText> lstSteps = new ArrayList<EditText>();
	private List<String> lstEffort = new ArrayList<String>();

	private EditText txtDescription;

	private EditText txtDuration;

	private Spinner spnEffort;

	private EditText txtName;

	private List<Spinner> lstSpinner;
	
	private List<Comment> comments;

	private Receipt edit;

	private DateFormat dateFormat;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.add_receipt);
		try {
			this.lstSpinner = new ArrayList<Spinner>();
			this.lstIngredient = AppActivity.facade.getAllIngredients();
			lstIngString.add("--");
			for (Ingredient ing : lstIngredient) {
				lstIngString.add(ing.getName());
			}
			comments = new ArrayList<Comment>();
		} catch (NoResultException | JSONException | InterruptedException | ExecutionException e) {
			Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
		}
		init();
	}

	/**
	 * Initialize the UI by implementing the functionability of the UI elements
	 */
	private void init() {
		dateFormat = android.text.format.DateFormat.getDateFormat(getApplicationContext());
		String[] efforts = getResources().getStringArray(R.array.lstEffort);
		for (String string : efforts) {
			lstEffort.add(string);
		}
		imgReceipt = (ImageView) findViewById(R.id.receiptImage);
		imgReceipt.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View view) {
				Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); 
                startActivityForResult(cameraIntent, CAMERA_REQUEST); 
			}
		});
		
		txtDescription = (EditText) findViewById(R.id.txtReceiptDescreption);
		txtDuration = (EditText) findViewById(R.id.txtReceiptDuration);
		txtName = (EditText) findViewById(R.id.txtReceiptName);
		spnEffort = (Spinner) findViewById(R.id.receiptEffort);
		
		Button add = (Button) findViewById(R.id.btnAdd);
		add.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				List<String> errors = getErrors();
				if(errors.size() == 0){
					Receipt receipt = new Receipt();
					receipt.setID(edit != null ? edit.getID() : -1);
					receipt.setDate(new Date());
					receipt.setDescription(txtDescription.getText().toString());
					receipt.setDuration(Integer.parseInt(txtDuration.getText().toString()));
					receipt.setEffort(spnEffort.getSelectedItem().toString());
					receipt.setLstIngredient(getIngredients());
					receipt.setLstStep(getSteps());
					receipt.setName(txtName.getText().toString());
					receipt.setUser(AppActivity.facade.getCurrentUser());
					try {
						if(receipt.getID() > 0){
							edit = AppActivity.facade.updateReceipt(receipt, false);
							Toast.makeText(getApplicationContext(), getResources().getString(R.string.receiptEdited), Toast.LENGTH_SHORT).show();
						} else {
							edit = AppActivity.facade.createReceipt(receipt);
							Toast.makeText(getApplicationContext(), getResources().getString(R.string.receiptAdded), Toast.LENGTH_SHORT).show();
						}
						for(Comment com : comments){
							com.setReciept(edit);
							AppActivity.facade.createComment(com);
						}
						AppActivity.tabHost.setCurrentTab(0);
						finish();
					} catch (NoReceiptException | NoIngredientsException
							| NoStepsException | InterruptedException | ExecutionException | JSONException | EmptyInputException e) {
						Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
					}
				} else {
					Toast.makeText(getApplicationContext(), getResources().getString(R.string.emptyInputs) + " " + MyTools.implode(", ", errors), Toast.LENGTH_LONG).show();
				}
			}
		});
		
		final EditText txtComment = (EditText) findViewById(R.id.txtCommentText);
		txtComment.setOnTouchListener(new OnTouchListener() {
			@SuppressLint("ClickableViewAccessibility")
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				v.setFocusable(true);
	            v.setFocusableInTouchMode(true);
				return false;
			}
		});
		Button btnAddComment = (Button) findViewById(R.id.btnAddComment);
		btnAddComment.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				String string = txtComment.getText().toString();
				if(!MyTools.isEmpty(string)){
					if(edit != null && edit.getID() > 0){
						Comment comment = new Comment(string, new Date(), AppActivity.facade.getCurrentUser());
						comment.setReciept(edit);
						try {
							AppActivity.facade.createComment(comment);
							edit.getLstComment().add(comment);
							showComments(edit.getLstComment());
							txtComment.setText("");
						} catch (EmptyInputException | InterruptedException | ExecutionException | JSONException e) {
							e.printStackTrace();
						}
					} else {
						Comment com = new Comment(string, new Date(), AppActivity.facade.getCurrentUser());
						comments.add(com);
						showComments(comments);
						txtComment.setText("");
					}
				} else {
					Toast.makeText(getApplicationContext(), getResources().getString(R.string.emptyComment), Toast.LENGTH_SHORT).show();
				}
			}
		});
		
		try{
			// when the chosen receipt's user is the current user the chosen receipt can be edited
			edit = (Receipt) getIntent().getSerializableExtra(ReceiptDetailActivity.ARG_ITEM);
			edit.setLstIngredient(AppActivity.facade.ingredientsByReceipt(edit));
			edit.setLstStep(AppActivity.facade.stepsByReceipt(edit));
			edit.setLstComment(AppActivity.facade.commentsByReceipt(edit));
			txtDescription.setText(edit.getDescription());
			txtName.setText(edit.getName());
			txtDuration.setText(edit.getDuration() + "");
			spnEffort.setSelection(lstEffort.indexOf(edit.getEffort()));
			new DownloadImageService((ImageView) findViewById(R.id.receiptImage)).execute(edit.getID() + ".png");
			for(Ingredient ing : edit.getLstIngredient()){
				initIngredients(ing.getID()+1, ing.getAmount(), ing.getTypeOfAmount());
			}
			if(cntContentsIng < MAX_ING){
				initIngredients(0, 0, "--");
			}
			for(Step step : edit.getLstStep()){
				initSteps(step.getDescription());
			}
			showComments(edit.getLstComment());
			add.setText(getResources().getString(R.string.btnEdit));
		} catch (Exception e){
			initIngredients(0, 0, "--");
			initSteps("");
		}
	}
	
	/**
	 * Generating a list with empty inputs
	 * @return
	 */
	protected List<String> getErrors() {
		List<String> result = new ArrayList<String>();
		if(MyTools.isEmpty(txtDuration.getText().toString())){
			result.add(getResources().getString(R.string.duration));
		}
		if(MyTools.isEmpty(txtDescription.getText().toString())){
			result.add(getResources().getString(R.string.receiptDescription));
		}
		if(MyTools.isEmpty(txtName.getText().toString())){
			result.add(getResources().getString(R.string.receiptName));
		}
		return result;
	}

	/**
	 * Creating the view for the comments.
	 * @param lstComment
	 */
	private void showComments(List<Comment> lstComment) {
		TableRow container = (TableRow) findViewById(R.id.comments);
		// first remove all
		container.removeAllViews();
		
		ScrollView sv = new ScrollView(this);
		LinearLayout ll = new LinearLayout(this);
		ll.setOrientation(LinearLayout.VERTICAL);
		
		// add for each comment a text
		for (Comment com : lstComment) {
			LinearLayout lContent = new LinearLayout(this);
			lContent.setOrientation(LinearLayout.VERTICAL);
			
			TextView txtUserName = new TextView(this);
			txtUserName.setText(com.getUser().getLoginName() + "(" + dateFormat.format(com.getDate()) +")");
			lContent.addView(txtUserName);
			
			TextView txtComment = new TextView(this);
			txtComment.setText(com.getText());
			txtComment.setSingleLine(false);
			txtComment.setImeOptions(EditorInfo.IME_FLAG_NO_ENTER_ACTION);
			txtComment.setMaxWidth(dpToPx(WIDHT_COMMENT));
			txtComment.setMinWidth(dpToPx(WIDHT_COMMENT));
			lContent.addView(txtComment);
			
			ll.addView(lContent);
		}
		sv.addView(ll);
		container.addView(sv);
	}

	/**
	 * Generates a list of steps by added steps
	 * @return
	 */
	protected List<Step> getSteps() {
		List<Step> result = new ArrayList<Step>();
		for (int i = 0; i < lstSteps.size(); i++) {
			String text = lstSteps.get(i).getText().toString();
			if(!MyTools.isEmpty(text)){
				Step tmp = new Step(i+1, text);
				result.add(tmp);
			}
		}
		return result;
	}
	
	/**
	 * Generates the list with ingredients by the selected ingredients
	 * @return
	 */
	protected List<Ingredient> getIngredients() {
		List<Ingredient> result = new ArrayList<Ingredient>();
		for (int i = 0; i < lstIngs.size(); i++) {
			int amount = Integer.parseInt(lstIngs.get(i).getText().toString());
			if(amount > 0){
				Ingredient tmp = lstIngredient.get(lstSpinner.get(i).getSelectedItemPosition()-1);
				tmp.setAmount(amount);
				result.add(tmp);
			}
		}
		return result;
	}

	/**
	 * Initialize the functionality for the steps
	 * @param text
	 */
	private void initSteps(String text) {
		TableRow container = (TableRow) findViewById(contentsStep[cntContentsStep++]);
		container.removeAllViews();
		ScrollView sv = new ScrollView(this);
		LinearLayout ll = new LinearLayout(this);
		ll.setOrientation(LinearLayout.VERTICAL);
		
		LinearLayout llCon = new LinearLayout(this);
	    
		TextView txtStep = new TextView(this);
		txtStep.setText(getResources().getString(R.string.step) + " " + cntContentsStep);
		llCon.addView(txtStep);
		
	    EditText txtStepDesc = new EditText(this);
	    txtStepDesc.setText(text);
	    txtStepDesc.setSingleLine(false);
	    txtStepDesc.setImeOptions(EditorInfo.IME_FLAG_NO_ENTER_ACTION);
	    txtStepDesc.setMinWidth(dpToPx(WIDTH_STEP));
	    txtStepDesc.setMaxWidth(dpToPx(WIDTH_STEP));
	    llCon.addView(txtStepDesc);
	    lstSteps.add(txtStepDesc);
	    
	    Button newStep = (Button) findViewById(R.id.newStep);
	    newStep.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				if(cntContentsStep <= MAX_STEP){
					initSteps("");
				}
			}
		});
	    
	    ll.addView(llCon);
		sv.addView(ll);
		container.addView(sv);
	}

	/**
	 * Initialize the functionality for the ingredients
	 * @param index
	 * @param amount
	 * @param typeOf
	 */
	private void initIngredients(int index, int amount, String typeOf) {
		TableRow container = (TableRow) findViewById(contentsIng[cntContentsIng]);
		container.removeAllViews();
		ScrollView sv = new ScrollView(this);
		LinearLayout ll = new LinearLayout(this);
		ll.setOrientation(LinearLayout.VERTICAL);
		
		LinearLayout llCon = new LinearLayout(this);
		final Spinner spinner = new Spinner(this);
	    ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, lstIngString);
	    spinner.setAdapter(spinnerArrayAdapter);
	    llCon.addView(spinner);
	    lstSpinner.add(spinner);
	    
	    EditText txtAmount = new EditText(this);
	    txtAmount.setText(amount+"");
	    txtAmount.setRawInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
	    llCon.addView(txtAmount);
	    lstIngs.add(txtAmount);
	    
	    final TextView txtTypeOf = new TextView(this);
	    txtTypeOf.setText(typeOf);
	    llCon.addView(txtTypeOf);
	    
	    ll.addView(llCon);
		sv.addView(ll);
		container.addView(sv);
		
		spinner.post(new Runnable() {
	    	public void run() {
	    		spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
					@Override
					public void onItemSelected(AdapterView<?> parent, View view,
							int pos, long id) {
						if(cntContentsIng <= MAX_ING){
							boolean add = true;
							for (Spinner spn : lstSpinner) {
								if(spn.getSelectedItemPosition() == 0){
									add = false;
								}
							}
							if(add){
								initIngredients(0, 0, "--");
							}
						}
						txtTypeOf.setText(lstIngredient.get(pos-1).getTypeOfAmount());
					}
					@Override
					public void onNothingSelected(AdapterView<?> arg0) {
					}
				});
	    	};
	    });
		spinner.setSelection(index-1);
		cntContentsIng++;
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// when a photo has been chosen
		if (requestCode == CAMERA_REQUEST && resultCode == RESULT_OK) {  
            Bitmap photo = (Bitmap) data.getExtras().get("data"); 
            imgReceipt.setImageBitmap(photo);
            scaleImage(imgReceipt, dpToPx(230));
            Toast.makeText(getApplicationContext(), getResources().getString(R.string.imgReceiptMessage), Toast.LENGTH_LONG).show();
        }  
	}
	
	private void scaleImage(ImageView view, int boundBoxInDp)
	{
	    // Get the ImageView and its bitmap
	    Drawable drawing = view.getDrawable();
	    Bitmap bitmap = ((BitmapDrawable)drawing).getBitmap();

	    // Get current dimensions
	    int width = bitmap.getWidth();
	    int height = bitmap.getHeight();

	    // Determine how much to scale: the dimension requiring less scaling is
	    // closer to the its side. This way the image always stays inside your
	    // bounding box AND either x/y axis touches it.
	    float xScale = ((float) boundBoxInDp) / width;
	    float yScale = ((float) boundBoxInDp) / height;
	    float scale = (xScale <= yScale) ? xScale : yScale;

	    // Create a matrix for the scaling and add the scaling data
	    Matrix matrix = new Matrix();
	    matrix.postScale(scale, scale);

	    // Create a new bitmap and convert it to a format understood by the ImageView
	    Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
	    @SuppressWarnings("deprecation")
		BitmapDrawable result = new BitmapDrawable(scaledBitmap);
	    width = scaledBitmap.getWidth();
	    height = scaledBitmap.getHeight();

	    // Apply the scaled bitmap
	    view.setImageDrawable(result);

	    // Now change ImageView's dimensions to match the scaled image
	    LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
	    params.width = width;
	    params.height = height;
	    view.setLayoutParams(params);
	}
	
	private int dpToPx(int dp)
	{
	    float density = getApplicationContext().getResources().getDisplayMetrics().density;
	    return Math.round((float)dp * density);
	}
	
}
